package cn.s1995.sloth.bizs.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.s1995.sloth.bizs.constant.SqlCst;
import cn.s1995.sloth.bizs.entity.Order;
import cn.s1995.sloth.bizs.entity.Prod;
import cn.s1995.sloth.bizs.mapper.DashboardMapper;
import cn.s1995.sloth.bizs.oo.req.ChartREQ;
import cn.s1995.sloth.bizs.oo.vo.ChartVO;
import cn.s1995.sloth.bizs.oo.vo.DashboardOrderStateVO;
import cn.s1995.sloth.bizs.oo.vo.DashboardStatisticsVO;
import cn.s1995.sloth.bizs.service.DashboardService;
import cn.s1995.sloth.bizs.service.OrderService;
import cn.s1995.sloth.bizs.service.ProdService;
import cn.s1995.sloth.common.core.util.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@AllArgsConstructor
public class DashboardServiceImpl implements DashboardService {

    private final OrderService orderService;

    private final ProdService prodService;

    private final DashboardMapper dashboardMapper;

    @Override
    public DashboardStatisticsVO getStatistics() {
        return dashboardMapper.getStatistics();
    }

    @Override
    public List<Order> getLatestOrders(Long limit) {
        return orderService.list(
                Wrappers.lambdaQuery(Order.class)
                        .orderByDesc(Order::getCreateTime, Order::getId)
                        .last(SqlCst.getLimitTarget(limit))
        );
    }

    @Override
    public DashboardOrderStateVO getStateOrders(ChartREQ req) {
        return dashboardMapper.getStateOrders(req);
    }

    @Override
    public List getRankingList(Integer type, Long limit) {
        switch (type) {
            // 1.产品销量排行
            case 1 -> {
                return prodService.list(
                        Wrappers.lambdaQuery(Prod.class)
                                .select(Prod::getId, Prod::getName, Prod::getPic, Prod::getBrief, Prod::getSaleNum)
                                .orderByDesc(Prod::getSaleNum)
                                .last(SqlCst.getLimitTarget(limit))
                );
            }
            // 2.店铺销量排行
            case 2 -> {
                return dashboardMapper.getRankingShopList(limit);
            }
        }

        return List.of();
    }

    @Override
    public List<ChartVO> getChart(ChartREQ req) {
        List<ChartVO> chartData = new ArrayList<>();

        Map<String, String> unitMap = new HashMap<>();
        unitMap.put(DateUtil.Unit.hour, ChartREQ.SqlGroup.hour);
        unitMap.put(DateUtil.Unit.day, ChartREQ.SqlGroup.day);

        // 如果入参时间开始时间和结束时间为同一天则按小时查询数据
        if (req.hasSameDay()) {
            req.setUnit(DateUtil.Unit.hour);
        }
        // sql分组统计值
        req.setSqlGroup(unitMap.get(req.getUnit()));

        // 类型：1.收益 2.订单 3.订单退款 4.用户增长 5.用户访问
        switch (req.getType()) {
            case ChartREQ.Type.income -> {
                chartData = dashboardMapper.getChartForIncome(req);
            }
            case ChartREQ.Type.order -> {
                chartData = dashboardMapper.getChartForOrder(req);
            }
            case ChartREQ.Type.orderRefund -> {
                chartData = dashboardMapper.getChartForOrderRefund(req);
            }
            case ChartREQ.Type.userGrowth -> {
                if (ArrayUtil.isEmpty(req.getRangeTime())) {
                    LocalDateTime now = LocalDateTime.now();
                    // 查询最近24小时节点的数据
                    req.setRangeTime(new String[]{DateUtil.format(now.plusHours(-23L)), DateUtil.format(now)});
                    req.setUnit(DateUtil.Unit.hour);
                    req.setSqlGroup(ChartREQ.SqlGroup.hour);
                }
                chartData = dashboardMapper.getChartForUserGrowth(req);
            }
            case ChartREQ.Type.userVisitor -> {
                chartData = dashboardMapper.getChartForUserVisitor(req);
            }
            default -> {
                log.warn("getChart未知类型：{}", req.getType());
            }
        }

        // 如果无入参时间且单位为day，则根据数据集进行对应处理
        if (ArrayUtil.isEmpty(req.getRangeTime()) && DateUtil.Unit.day.equals(req.getUnit())) {
            chartData = handleDayChartData(chartData, req);
        }

        return buildChartData(chartData, req);
    }


    /**
     * 处理单位为day的数据
     *
     * @param chartData
     * @param req
     * @return
     */
    private List<ChartVO> handleDayChartData(List<ChartVO> chartData, ChartREQ req) {
        // 如果数据集为空则暂不处理
        if (CollUtil.isEmpty(chartData)) {
            return chartData;
        }

        // 只有一条数据时，设置单位hour,根据类型查询当天对应数据
        if (CollUtil.isNotEmpty(chartData) && chartData.size() == 1) {
            ChartVO chartVO = chartData.get(0);
            req.setUnit(DateUtil.Unit.hour);
            req.setSqlGroup(ChartREQ.SqlGroup.hour);
            req.setRangeTime(new String[]{chartVO.getLabel() + " 00:00:00", chartVO.getLabel() + " 23:59:59"});
            // 类型：1.收益 2.订单 3.订单退款 4.用户增长 5.用户访问
            switch (req.getType()) {
                case ChartREQ.Type.income -> {
                    return dashboardMapper.getChartForIncome(req);
                }
                case ChartREQ.Type.order -> {
                    return dashboardMapper.getChartForOrder(req);
                }
                case ChartREQ.Type.orderRefund -> {
                    return dashboardMapper.getChartForOrderRefund(req);
                }
                case ChartREQ.Type.userGrowth -> {
                    return dashboardMapper.getChartForUserGrowth(req);
                }
                case ChartREQ.Type.userVisitor -> {
                    return dashboardMapper.getChartForUserVisitor(req);
                }
                default -> {
                    return chartData;
                }
            }
        }

        return chartData;
    }


    /**
     * 构建图表数据
     *
     * @param data 数据集
     * @param req  请求参数
     * @return
     */
    private List<ChartVO> buildChartData(List<ChartVO> data, ChartREQ req) {
        // 返回结果
        List<ChartVO> res = new ArrayList<>();
        // 时间范围，根据入参时间范围，取出时间范围
        List<String> rangeTimeList = DateUtil.getAroundRangeTime(req.getRangeTime(), req.getUnit());

        // 如果没有入参时间范围则根据数据集，取出时间范围
        if (CollUtil.isEmpty(rangeTimeList) && CollUtil.isNotEmpty(data) && data.size() > 1) {
            rangeTimeList = DateUtil.getAroundRangeTime(new String[]{data.get(0).getLabel(), data.get(data.size() - 1).getLabel()}, req.getUnit());
        }

        // 如果时间范围为空则直接返回数据集
        // if (CollUtil.isEmpty(rangeTimeList)) {
        //     return data;
        // }

        // 如果时间范围&数据集为空
        if (CollUtil.isEmpty(rangeTimeList) && CollUtil.isEmpty(data)) {
            // 构建近七天时间范围
            LocalDateTime now = LocalDateTime.now();
            rangeTimeList = DateUtil.getAroundRangeTime(new String[]{DateUtil.format(now.plusDays(-6)), DateUtil.format(now)}, req.getUnit());
        }

        // 数据映射：label -> value
        Map<String, String> map = data.stream().collect(Collectors.toMap(e -> e.getLabel(), e -> e.getValue()));
        for (String s : rangeTimeList) {
            res.add(
                    ChartVO.builder()
                            .label(s)
                            .value(Optional.ofNullable(map.get(s)).orElse("0"))
                            .build()
            );
        }

        return res;
    }


}
